{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# Conversation with a ReAct Agent\n",
    "\n",
    "In this example, we will show you\n",
    "- How to create a new service function for the tool agent to use\n",
    "- How to use the ServiceToolkit module pre-process the tool functions for LLMs\n",
    "- How to use the built-in ReAct agent to solve a problem\n",
    "\n",
    "## Prerequisites\n",
    "\n",
    "- Follow [READMD.md](https://github.com/modelscope/agentscope) to install AgentScope. \n",
    "- Prepare a model configuration. AgentScope supports both local deployed model services (CPU or GPU) and third-party services. More details and example model configurations please refer to our [tutorial](https://modelscope.github.io/agentscope/en/tutorial/203-model.html).\n",
    "- [Optional] A bing (or google) search API key is suggested to experience the web search function. Here we take bing search as an example. \n",
    "\n",
    "## Note\n",
    "\n",
    "- The example is tested with the following models. For other models, you may need to adjust the prompt.\n",
    "    - gpt-4\n",
    "    - gpt-3.5-turbo\n",
    "    - qwen-max"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "6b868755498c634a"
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [],
   "source": [
    "YOUR_MODEL_CONFIGURATION_NAME = \"{YOUR_MODEL_CONFIGURATION_NAME}\"\n",
    "\n",
    "YOUR_MODEL_CONFIGURATION = {\n",
    "    \"model_type\": \"xxx\", \n",
    "    \"config_name\": YOUR_MODEL_CONFIGURATION_NAME\n",
    "    \n",
    "    # ...\n",
    "}\n",
    "\n",
    "BING_API_KEY = \"{BING_API_KEY}\""
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-04-16T01:51:29.449020Z",
     "start_time": "2024-04-16T01:51:29.435200Z"
    }
   },
   "id": "8355a19d4eb5af55"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Step 1: Customize a Service Function\n",
    "\n",
    "Taking `execute_python_code` as an example, we will show how to create a new service function that can be processed by `ServiceToolkit` module.\n",
    "\n",
    "In AgentScope, a service function should have the following structure:\n",
    "\n",
    "- A well formatted docstring (Google style is recommended), which contains\n",
    "    - A brief description of function in docstring.\n",
    "    - A brief description of the input arguments.\n",
    "    - Wrap the output and execution status into a `ServiceResponse` object.\n",
    "\n",
    "The following is a simple example of a service function that executes Python code and captures the output. (Also, you can use the `execute_python_code` function in the `agentscope.service` module directly, which provide more features.)\""
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "8ef2e3639e08cc0a"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [],
   "source": [
    "from agentscope.service import ServiceResponse, ServiceExecStatus\n",
    "import sys, io\n",
    "\n",
    "def execute_python_code(code: str) -> ServiceResponse:\n",
    "    \"\"\"\n",
    "    Execute Python code and capture the output. Note you must `print` the output to get the result.\n",
    "    Args:\n",
    "        code (`str`):\n",
    "            The Python code to be executed.\n",
    "    \"\"\"  # noqa\n",
    "\n",
    "    # Create a StringIO object to capture the output\n",
    "    old_stdout = sys.stdout\n",
    "    new_stdout = io.StringIO()\n",
    "    sys.stdout = new_stdout\n",
    "\n",
    "    try:\n",
    "        # Using `exec` to execute code\n",
    "        exec(code)\n",
    "    except Exception as e:\n",
    "        # If an exception occurs, capture the exception information\n",
    "        output = str(e)\n",
    "        status = ServiceExecStatus.ERROR\n",
    "    else:\n",
    "        # If the execution is successful, capture the output\n",
    "        output = new_stdout.getvalue()\n",
    "        status = ServiceExecStatus.SUCCESS\n",
    "    finally:\n",
    "        # Recover the standard output\n",
    "        sys.stdout = old_stdout\n",
    "\n",
    "    # Wrap the output and status into a ServiceResponse object\n",
    "    return ServiceResponse(status, output)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-04-16T01:51:38.238708Z",
     "start_time": "2024-04-16T01:51:36.965973Z"
    }
   },
   "id": "9d34e13ea408f21d"
  },
  {
   "cell_type": "markdown",
   "source": [
    "After defining the service function, we try to use `ServiceToolkit` to pre-process the tool functions for LLMs. Here, we take `execute_python_code` function as example and observe the JSON schema generated by `service_toolkit`."
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "a97eab8ecc98ed89"
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "    \"execute_python_code\": {\n",
      "        \"type\": \"function\",\n",
      "        \"function\": {\n",
      "            \"name\": \"execute_python_code\",\n",
      "            \"description\": \"Execute Python code and capture the output. Note you must `print` the output to get the result.\",\n",
      "            \"parameters\": {\n",
      "                \"type\": \"object\",\n",
      "                \"properties\": {\n",
      "                    \"code\": {\n",
      "                        \"type\": \"string\",\n",
      "                        \"description\": \"The Python code to be executed.\"\n",
      "                    }\n",
      "                },\n",
      "                \"required\": [\n",
      "                    \"code\"\n",
      "                ]\n",
      "            }\n",
      "        }\n",
      "    }\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "from agentscope.service import ServiceToolkit\n",
    "\n",
    "service_toolkit = ServiceToolkit()\n",
    "service_toolkit.add(execute_python_code)\n",
    "\n",
    "import json\n",
    "print(json.dumps(service_toolkit.json_schemas, indent=4))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-04-16T01:51:43.581845Z",
     "start_time": "2024-04-16T01:51:43.578326Z"
    }
   },
   "id": "1ef000177bccd2a5"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Step 2: Prepare all tool functions for the agent\n",
    "Similar as above, we can create different service functions, or use the built-in functions in `agentscope.service` module as follows. More service functions can be found under the `agentscope.service` module."
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "ebd210b104459fb5"
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [],
   "source": [
    "from agentscope.service import (\n",
    "    bing_search, # or google_search,\n",
    "    read_text_file,\n",
    "    write_text_file, \n",
    ")\n",
    "\n",
    "# Deal with arguments that need to be input by developers\n",
    "service_toolkit.add(bing_search, api_key=BING_API_KEY, num_results=3)\n",
    "service_toolkit.add(read_text_file)\n",
    "service_toolkit.add(write_text_file)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-04-16T01:52:00.399308Z",
     "start_time": "2024-04-16T01:52:00.393475Z"
    }
   },
   "id": "9c7f4d40bfab5003"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Step 3: Create a React Agent"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "794e63922cd0c954"
  },
  {
   "cell_type": "markdown",
   "source": [
    "A ReAct Agent is built in AgentScope to show how to construct complex reasoning processes. It solves a problem by a loop of \"thought\", \"action\" and \"observation\" steps. \n",
    "\n",
    "- thought: analyze and decide next action (the tools to use)\n",
    "- action: execute the action (the tool function)\n",
    "- observation: observe the execution results\n",
    "\n",
    "In AgentScope, we implement the above steps in a `ReActAgent` class. Let's first taking a look at its system prompt. "
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "3f2e4ad0458966cd"
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2024-04-16 09:52:31.694 | INFO     | agentscope.models:read_model_configs:181 - Load configs for model wrapper: qwen, gpt-4, ollama\n",
      "2024-04-16 09:52:31.711 | INFO     | agentscope.utils.monitor:_create_monitor_table:341 - Init [monitor_metrics] as the monitor table\n",
      "2024-04-16 09:52:31.712 | INFO     | agentscope.utils.monitor:_create_monitor_table:342 - Init [monitor_metrics_quota_exceeded] as the monitor trigger\n",
      "2024-04-16 09:52:31.712 | INFO     | agentscope.utils.monitor:__init__:311 - SqliteMonitor initialization completed at [./runs/run_20240416-095137_jgmih8/agentscope.db]\n",
      "2024-04-16 09:52:31.716 | INFO     | agentscope.models.model:__init__:200 - Initialize model by configuration [qwen]\n",
      "2024-04-16 09:52:31.718 | INFO     | agentscope.utils.monitor:register:362 - Register metric [qwen-max.call_counter] to SqliteMonitor with unit [times] and quota [None]\n",
      "2024-04-16 09:52:31.719 | INFO     | agentscope.utils.monitor:register:362 - Register metric [qwen-max.prompt_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
      "2024-04-16 09:52:31.721 | INFO     | agentscope.utils.monitor:register:362 - Register metric [qwen-max.completion_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
      "2024-04-16 09:52:31.722 | INFO     | agentscope.utils.monitor:register:362 - Register metric [qwen-max.total_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
      "################################################################################\n",
      "You're a helpful assistant. Your name is assistant.\n",
      "\n",
      "## Tool Functions:\n",
      "The following tool functions are available in the format of\n",
      "```\n",
      "{index}. {function name}: {function description}\n",
      "{argument1 name} ({argument type}): {argument description}\n",
      "{argument2 name} ({argument type}): {argument description}\n",
      "...\n",
      "```\n",
      "\n",
      "1. execute_python_code: Execute Python code and capture the output. Note you must `print` the output to get the result.\n",
      "\tcode (string): The Python code to be executed.\n",
      "2. bing_search: Search question in Bing Search API and return the searching results\n",
      "\tquestion (string): The search query string.\n",
      "3. read_text_file: Read the content of the text file.\n",
      "\tfile_path (string): The path to the text file to be read.\n",
      "4. write_text_file: Write content to a text file.\n",
      "\tfile_path (string): The path to the file where content will be written.\n",
      "\toverwrite (boolean): Whether to overwrite the file if it already exists.\n",
      "\tcontent (string): Content to write into the file.\n",
      "\n",
      "## What You Should Do:\n",
      "1. First, analyze the current situation, and determine your goal.\n",
      "2. Then, check if your goal is already achieved. If so, try to generate a response. Otherwise, think about how to achieve it with the help of provided tool functions.\n",
      "3. Respond in the required format.\n",
      "\n",
      "## Note:\n",
      "1. Fully understand the tool functions and their arguments before using them.\n",
      "2. You should decide if you need to use the tool functions, if not then return an empty list in \"function\" field.\n",
      "3. Make sure the types and values of the arguments you provided to the tool functions are correct.\n",
      "4. Don't take things for granted. For example, where you are, what's the time now, etc. You can try to use the tool functions to get information.\n",
      "5. If the function execution fails, you should analyze the error and try to solve it.\n",
      "\n",
      "################################################################################\n"
     ]
    }
   ],
   "source": [
    "from agentscope.agents import ReActAgent\n",
    "import agentscope\n",
    "\n",
    "agentscope.init(\n",
    "    model_configs=YOUR_MODEL_CONFIGURATION,\n",
    "    project=\"Conversation with ReActAgent\",\n",
    ")\n",
    "\n",
    "agent = ReActAgent(\n",
    "    name=\"assistant\",\n",
    "    model_config_name=YOUR_MODEL_CONFIGURATION_NAME,\n",
    "    service_toolkit=service_toolkit, \n",
    "    verbose=True, # set verbose to True to show the reasoning process\n",
    ")\n",
    "\n",
    "print(\"#\"*80)\n",
    "print(agent.sys_prompt)\n",
    "print(\"#\"*80)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-04-16T01:52:31.741951Z",
     "start_time": "2024-04-16T01:52:31.675Z"
    }
   },
   "id": "ad793ef9e2bb7945"
  },
  {
   "cell_type": "markdown",
   "source": [
    "As shown above, the system prompt is consisted of \n",
    "\n",
    "- the description of the agent\n",
    "- the description of tool functions\n",
    "- some notices for the large language models\n",
    "\n",
    "Besides, when ReAct Agent generates \"thought\", we use the following prompt to guide the generation. It's wrapped into a message with `role` field as `\"system\"` to distinguish from the user's input.\n",
    "\n",
    "```python\n",
    "# print(agent.parser.format_instruction)\n",
    "\"\"\"\n",
    "You should respond a json object in a json fenced code block as follows:\n",
    "```json\n",
    "{\n",
    "\t\"thought\": \"what you thought\", \n",
    "\t\"speak\": \"what you speak\", \n",
    "\t\"function\": [\n",
    "\t\t{\n",
    "\t\t\t\"name\": \"{function name}\", \n",
    "\t\t\t\"arguments\": {\n",
    "\t\t\t\t\"{argument1 name}\": xxx, \n",
    "\t\t\t\t\"{argument2 name}\": xxx\n",
    "\t\t\t}\n",
    "\t\t}\n",
    "\t]\n",
    "}```\n",
    "\"\"\"\n",
    "```\n",
    "\n",
    "When the `function` field in the response dictionary is empty, the agent will end the \"reasoning-acting\" loop and return the final response to the user. \n",
    "\n",
    "More implementation details please refer to the [source code](../../src/agentscope/agents/react_agent.py)."
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "ca977a86cdd1b482"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Step 4: Try to Solve a Problem with the ReAct Agent\n",
    "\n",
    "Now, let's try to ask the example question in the ReAct Paper: `\"Aside from the Apple Remote, what other device can control the program Apple Remote was originally designed to interact with?\"` as follows"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "b6e2e7a1c5fac168"
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [],
   "source": [
    "from agentscope.message import Msg\n",
    "\n",
    "msg_question = Msg(\n",
    "    name=\"user\", \n",
    "    content=\"Aside from the Apple Remote, what other device can control the program Apple Remote was originally designed to interact with?\", \n",
    "    role=\"user\"\n",
    ")\n",
    "\n",
    "res = agent(msg_question)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-04-16T02:02:06.982344Z",
     "start_time": "2024-04-16T02:00:21.137787Z"
    }
   },
   "id": "be6ffe0c91474589"
  },
  {
   "cell_type": "markdown",
   "source": [
    "The above example is very interesting! Because the ReAct algorithm is famous and its example question occurs in many different websites, the results in the first searching are all about ReAct algorithm, rather than the answer to the question. \n",
    "\n",
    "Knowing this, in the reasoning step of the second iteration, the ReAct agent decides to rewrite the query and re-search in the website. It finally finds the answer in the third iteration. \n",
    "\n",
    "The behavior of the ReAct agent is unexpected and interesting. It shows that the ReAct agent can learn from the previous results and adjust its behavior in the next iteration. \n",
    "\n",
    "You can use the following code to build a conversation with the ReAct agent, and we also provide [completed code](./code/conversation_with_react_agent.py). \n",
    "\n",
    "```python\n",
    "from agentscope.agents import UserAgent\n",
    "\n",
    "user = UserAgent(name=\"User\")\n",
    "\n",
    "x = None\n",
    "while True:\n",
    "    x = user(x)\n",
    "    if x.content == \"exit\":\n",
    "        break\n",
    "    x = agent(x)\n",
    "```"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "602ccd32a8514db7"
  },
  {
   "cell_type": "markdown",
   "source": [
    "In the end, we print the memory of the agent to show the reasoning process."
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "a1b8d2b3993d36a"
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "    {\n",
      "        \"id\": \"d71ec3345ca3452697d33da946d3725f\",\n",
      "        \"timestamp\": \"2024-03-26 19:19:57\",\n",
      "        \"name\": \"system\",\n",
      "        \"content\": \"You are a helpful assistant.\\n\\nThe following tool functions are available in the format of\\n```\\n{index}. {function name}: {function description}\\n    {argument name} ({argument type}): {argument description}\\n    ...\\n```\\n\\nTool Functions:\\n1. bing_search: Search question in Bing Search API and return the searching results\\n\\tquestion (string): The search query string.\\n2. execute_python_code: Execute Python code and capture the output. Note you must `print` the output to get the result.\\n\\tcode (string): The Python code to be executed.\\n3. read_text_file: Read the content of the text file.\\n\\tfile_path (string): The path to the text file to be read.\\n4. write_text_file: Write content to a text file.\\n\\toverwrite (boolean): Whether to overwrite the file if it already exists.\\n\\tfile_path (string): The path to the file where content will be written.\\n\\tcontent (string): Content to write into the file.\\n\\nNotice:\\n1. Fully understand the tool function and its arguments before using it.\\n2. Only use the tool function when it's necessary.\\n3. Check if the arguments you provided to the tool function is correct in type and value.\\n4. You can't take some problems for granted. For example, where you are, what's the time now, etc. But you can try to use the tool function to solve the problem.\\n5. If the function execution fails, you should analyze the error and try to solve it.\\n\\n\",\n",
      "        \"url\": null,\n",
      "        \"role\": \"system\"\n",
      "    },\n",
      "    {\n",
      "        \"id\": \"2a43c07ef95644aa9eb25b28731cd65c\",\n",
      "        \"timestamp\": \"2024-03-26 19:19:57\",\n",
      "        \"name\": \"user\",\n",
      "        \"content\": \"Aside from the Apple Remote, what other device can control the program Apple Remote was originally designed to interact with?\",\n",
      "        \"url\": null,\n",
      "        \"role\": \"user\"\n",
      "    },\n",
      "    {\n",
      "        \"id\": \"4a25ccc466f34653ac6e6acb86fc24d6\",\n",
      "        \"timestamp\": \"2024-03-26 19:20:02\",\n",
      "        \"name\": \"assistant\",\n",
      "        \"content\": {\n",
      "            \"thought\": \"I need to search for information about what other devices can control the program that the Apple Remote was originally designed to interact with.\",\n",
      "            \"speak\": \"Let me find that information for you.\",\n",
      "            \"function\": [\n",
      "                {\n",
      "                    \"name\": \"bing_search\",\n",
      "                    \"arguments\": {\n",
      "                        \"question\": \"What devices can control the program Apple Remote was designed for?\"\n",
      "                    }\n",
      "                }\n",
      "            ]\n",
      "        },\n",
      "        \"url\": null,\n",
      "        \"role\": \"assistant\"\n",
      "    },\n",
      "    {\n",
      "        \"id\": \"253d8cc15548499e97259d5fedde92f7\",\n",
      "        \"timestamp\": \"2024-03-26 19:20:03\",\n",
      "        \"name\": \"system\",\n",
      "        \"content\": \"Execution Results:\\n1. bing_search:\\n    [EXECUTE STATUS]: SUCCESS\\n    [EXECUTE RESULT]: [{'title': '《ReAct: SYNERGIZING REASONING AND ACTING IN ...', 'link': 'https://www.cnblogs.com/LittleHann/p/17541295.html', 'snippet': 'Aside from the Apple Remote, what other devices can control the program Apple Remote was originally designed to interact with? 我们可以看到该模型生成了任务解决轨迹（思考、行动）。'}, {'title': 'REACT：在大模型中协同推理与行动，使其能够解决推理和 ...', 'link': 'https://baijiahao.baidu.com/s?id=1775590643651365661', 'snippet': 'Q：Aside from the Apple Remote, what other device can control the program Apple Remote was originally designed to intect with? 除了苹果遥控器之外，还有哪些设备可以控制最初设计用于连接的苹果遥控器所配合的程序？'}, {'title': 'ReAct Prompting | Prompt Engineering Guide', 'link': 'https://www.promptingguide.ai/techniques/react', 'snippet': 'Aside from the Apple Remote, what other devices can control the program Apple Remote was originally designed to interact with? Note that in-context examples are also added to the prompt but we exclude that here for simplicity.'}]\\n\",\n",
      "        \"url\": null,\n",
      "        \"role\": \"system\"\n",
      "    },\n",
      "    {\n",
      "        \"id\": \"2346ccec579b48848a669d9f16b53c49\",\n",
      "        \"timestamp\": \"2024-03-26 19:20:10\",\n",
      "        \"name\": \"assistant\",\n",
      "        \"content\": {\n",
      "            \"thought\": \"The search results did not provide a clear answer to the question. I need to refine the search query to get more specific results.\",\n",
      "            \"speak\": \"I'm sorry, I couldn't find a clear answer. Let me try a different search.\",\n",
      "            \"function\": [\n",
      "                {\n",
      "                    \"name\": \"bing_search\",\n",
      "                    \"arguments\": {\n",
      "                        \"question\": \"What devices can control Apple TV other than Apple Remote?\"\n",
      "                    }\n",
      "                }\n",
      "            ]\n",
      "        },\n",
      "        \"url\": null,\n",
      "        \"role\": \"assistant\"\n",
      "    },\n",
      "    {\n",
      "        \"id\": \"67d707e4c0d44751aae5c5bbbe978f16\",\n",
      "        \"timestamp\": \"2024-03-26 19:20:11\",\n",
      "        \"name\": \"system\",\n",
      "        \"content\": \"Execution Results:\\n1. bing_search:\\n    [EXECUTE STATUS]: SUCCESS\\n    [EXECUTE RESULT]: [{'title': 'Use other remotes to control Apple TV - Apple Support', 'link': 'https://support.apple.com/guide/tv/use-other-remotes-atvb0410f604/tvos', 'snippet': 'Table of Contents. Use other remotes to control Apple TV. You can use a supported TV or receiver remote, a network-based remote for home-control systems, or an infrared remote (commonly known as a universal remote) to control Apple TV.'}, {'title': '4 Siri Remote Alternatives You Can Use to Control Your Apple TV - MUO', 'link': 'https://www.makeuseof.com/alternative-apple-tv-remotes/', 'snippet': \\\"Fortunately, if you find yourself looking for alternatives to control your Apple TV, there are several good options for you. You can use other Apple devices to operate the Apple TV, or even affordable Bluetooth accessories. We'll highlight the best alternatives to the Apple TV remote. 1. Use Your iPhone or iPad to Control the Apple TV\\\"}, {'title': 'Apple TV Siri Remote: How to control TVs and receivers - 9to5Mac', 'link': 'https://9to5mac.com/2021/05/27/apple-tv-siri-remote-control-tv-receiver/', 'snippet': 'The old Siri Remote and Apple TV Remote also feature this functionality, but without a dedicated power button, it’s less convenient and intuitive to use. Another benefit of HDMI-CEC is that...'}]\\n\",\n",
      "        \"url\": null,\n",
      "        \"role\": \"system\"\n",
      "    },\n",
      "    {\n",
      "        \"id\": \"7c36f98d1c204a03941375bef1eb44ee\",\n",
      "        \"timestamp\": \"2024-03-26 19:20:19\",\n",
      "        \"name\": \"assistant\",\n",
      "        \"content\": {\n",
      "            \"thought\": \"The search results provided a clear answer to the question. Other than the Apple Remote, you can use a supported TV or receiver remote, a network-based remote for home-control systems, an infrared remote (commonly known as a universal remote), or other Apple devices like an iPhone or iPad to control the Apple TV.\",\n",
      "            \"speak\": \"Other than the Apple Remote, you can use a supported TV or receiver remote, a network-based remote for home-control systems, an infrared remote (commonly known as a universal remote), or other Apple devices like an iPhone or iPad to control the Apple TV.\"\n",
      "        },\n",
      "        \"url\": null,\n",
      "        \"role\": \"assistant\"\n",
      "    }\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "print(json.dumps(agent.memory.get_memory(), indent=4, ensure_ascii=False))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-26T12:08:33.469827Z",
     "start_time": "2024-03-26T12:08:33.456020Z"
    }
   },
   "id": "5e099490946662f1"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
